import React, { useEffect, useState, useCallback, useMemo } from "react";
import styled from "styled-components";

const AppWrap = styled.div`
  text-align: center;
`;
const AppHeader = styled.header`
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
`;
const TimeString = styled.div`
  cursor: pointer;
`;

function useInfoHook() {
  const [info, setInfo] = useState(new Date().toString());
  const [time, setTime] = useState(1000);

  // useEffect的参数是一个函数，组件每次渲染之后，都会调用这个函数参数，
  // 这样就达到了 componentDidMount 和 componentDidUpdate 一样的效果
  // 实useEffect还接受第二个参数(数组)，第一次运行后，这个参数的值会被保存在缓存中，
  // 第二次运行到这里，React会把这个参数和缓存中的值做比较，如果二者相同，就不执行里面的函数
  // 需要注意的是，useEffect的第二个参数传空数组，它就等价于只在componentDidMount的时候执行
  useEffect(() => {
    setTimeout(async () => {
      await setInfo(new Date().toString());
    }, time);
  });

  return { info, setInfo, time, setTime };
}

function App(props) {
  const { info } = useInfoHook();

  // useMemo和useCallback都会在组件第一次渲染的时候执行，之后会在其依赖的变量发生改变时再次执行；
  // 并且这两个hooks都返回缓存的值，useMemo返回缓存的变量，useCallback返回缓存的函数。
  const handleTimeChange = useCallback(() => {
    console.log("由于依赖是空，这里的info缓存了初始值，不会变化", info);
    // 由于依赖是空，这里的info缓存了初始值，不会变化。
  }, []);
  const currentInfo = useMemo(() => {
    // memo有点类似于vue中的computed
    return `当前时间是：${info}`;
  }, [info]);

  return (
    <AppWrap>
      <AppHeader>
        <h1>React Hooks DEMO</h1>
        <TimeString onClick={handleTimeChange}>{currentInfo}</TimeString>
      </AppHeader>
    </AppWrap>
  );
}

export default App;
